package com.mercury.base.result;

import com.mercury.base.exception.MercuryException;
import com.mercury.base.result.code.BaseCode;
import com.mercury.base.result.code.IRespCode;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.beans.ConstructorProperties;
import java.io.Serializable;
import java.util.function.Function;

/**
 * @author mercury
 * @date 2020/10/11 2:56 下午
 */
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@NoArgsConstructor
public class ResultVo<E> extends BaseResultCoreResult<E> implements Serializable {

    private static final long serialVersionUID = 8960424786737581150L;

    public static <E> ResultVo<E> ok() {
        return ok(null);
    }

    public static <E> ResultVo<E> ok(E data) {
        return build(BaseCode.SUCCESS, data);
    }

    public static <E> ResultVo<E> err(IRespCode code) {
        return err(code, code.getMessage());
    }

    public static <E> ResultVo<E> err(IRespCode code, String message) {
        return err(code.getRespCode(), message);
    }

    public static <E> ResultVo<E> err(IRespCode code, E data) {
        return build(code.getRespCode(), code.getMessage(), data);
    }

    public static <E> ResultVo<E> err(String code, String message, E data) {
        return build(code, message, data);
    }

    public static <E> ResultVo<E> err(String message) {
        return err(BaseCode.SERVER_ERROR.getRespCode(), message);
    }

    public static <E> ResultVo<E> err(String code, String message) {
        if (code == null) {
            return err(message);
        }
        return build(code, message, null);
    }

    public static <E> ResultVo<E> build(IRespCode code) {
        return build(code, null);
    }

    public static <E> ResultVo<E> build(IRespCode code, E data) {
        return build(code.getRespCode(), code.getMessage(), data);
    }

    public static <E> ResultVo<E> build(String code, String message, E data) {
        return new ResultVo<>(code, message, data);
    }

    public static <E> ResultVo<E> with(Throwable e) {
        if (e instanceof MercuryException) {
            return err(((MercuryException) e).getCode(), e.getMessage());
        }
        if (e != null) {
            return err(BaseCode.SERVER_ERROR, e.getMessage());
        }
        return err(BaseCode.SERVER_ERROR);
    }

    @ConstructorProperties({"retcode", "message", "data"})
    public ResultVo(String retcode, String message, E data) {
        super(retcode, message, data);
    }

    public <T> ResultVo<T> map(Function<E, T> mapper) {
        T data = mapper.apply(getData());
        return new ResultVo<>(getCode(), getMessage(), data);
    }
}
